寄生组合式继承(推荐 Es6,过时禁止使用的)
寄生组合式继承是一种结合了寄生式继承和组合继承的继承模式,旨在解决组合继承中调用父类构造函数两次的问题。
寄生组合式继承:
- 寄生组合式继承是在组合继承的基础上,优化原型链继承部分,避免了父类构造函数被调用两次的问题。
javascriptfunction Parent(name) { this.name = name; } Parent.prototype.sayHello = function () { console.log("Hello, I am " + this.name); }; function Child(name) { Parent.call(this, name); // 构造函数继承 } Child.prototype = Object.create(Parent.prototype); // 优化原型链继承 Child.prototype.constructor = Child; // 修正构造函数指向 var child = new Child("Child"); child.sayHello(); // 输出 "Hello, I am Child"
缺陷例子
依然调用了两次父类构造函数:虽然寄生组合式继承尝试通过在子类构造函数中调用父类构造函数来避免调用父类构造函数两次的问题,但其核心仍然是通过 Object.create() 方法创建了一个父类的实例,并将其赋值给子类的原型。这意味着在子类原型上仍然存在一份父类的实例,依然会导致父类构造函数被调用两次。
存在原型链上的冗余属性:由于寄生组合式继承仍然使用了组合继承的原型链继承方式,因此子类原型上会存在父类实例的一个副本,导致原型链上存在冗余的属性。
无法避免父类构造函数中的属性被重复初始化:由于在寄生组合式继承中仍然调用了父类构造函数,因此父类构造函数内的属性会被初始化两次,无法避免这个问题。
复杂度较高:尽管寄生组合式继承试图解决组合继承的一些问题,但它的实现相对复杂,包含了较多的代码,增加了阅读和维护的难度。
难以理解:由于寄生组合式继承结合了多种继承方式,因此对于初学者来说,可能难以理解其内部的实现机制和工作原理。
js
// 父类构造函数
function Parent(name) {
this.name = name;
this.colors = ["red", "blue", "green"];
}
// 父类原型方法
Parent.prototype.sayHello = function () {
console.log("Hello, I'm " + this.name);
};
// 寄生组合式继承
function inheritPrototype(subType, superType) {
var prototype = Object.create(superType.prototype); // 创建父类原型的副本
prototype.constructor = subType; // 修正子类原型的构造函数
subType.prototype = prototype; // 将子类原型指向父类原型的副本
}
// 子类构造函数
function Child(name, age) {
Parent.call(this, name); // 调用父类构造函数一次
this.age = age;
}
// 使用寄生组合式继承
inheritPrototype(Child, Parent);
// 创建子类实例
var child1 = new Child("Alice", 10);
var child2 = new Child("Bob", 12);
// 修改
child1.colors.push("yellow");
// 问题1:依然调用了两次父类构造函数
console.log(child1.colors); // 输出: Alice
console.log(child1.colors); // 输出: Alice
console.log(child1.name); // 输出: Alice
console.log(child2.name); // 输出: Bob
// 问题2:存在原型链上的冗余属性
console.log(child1.colors === child2.colors); // 输出: false
// 问题3:无法避免父类构造函数中的属性被重复初始化
console.log(child1.colors); // 输出: ["red", "blue", "green"]